/*
 * Copyright (c) 2018-2024 北京华恒盛世科技有限公司
 * QUICKPOOL is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *     http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
*/

#include "xdrbase.h"
#include "channel.h"
#include "api.h"

char * 
client_peekjob(JOBID_T jobid)
{
    if (jobid <= 0) {
        quickpool_errno = ERROR_ARGUMENT;
        log_message(ERR, NOCLASS, "Job ID is not specified.");
        return NULL;
    }

    struct request peekRequest;
    peekRequest.number = 1;
    peekRequest.keyvalues = (struct keyvalue *)calloc(1, sizeof(struct keyvalue));
    if (NULL == peekRequest.keyvalues) {
        quickpool_errno = ERROR_MEMORY;
        log_message(ERR, NOCLASS, STR_FUNC_D_FAIL_M, __func__, "calloc",
                    sizeof(struct keyvalue));
        return NULL;
    }

    peekRequest.keyvalues[0].key = REQUEST_KEY_JOBIDS;
    peekRequest.keyvalues[0].value = (char *)calloc(32, sizeof(char));
    if (NULL == peekRequest.keyvalues[0].value) {
        quickpool_errno = ERROR_MEMORY;
        log_message(ERR, NOCLASS, STR_FUNC_D_FAIL_M, __func__, "calloc", 32);
        return NULL;
    }
    snprintf(peekRequest.keyvalues[0].value, 32, "%lld", jobid);

    struct auth auth;
    gf_set_auth(&auth, commandParams[AUTH_KIND].string_value);

    unsigned int size;
    size = gf_xdrsize_request(&peekRequest);
    size += gf_xdrsize_auth(&auth);
    size += HEADER_LEN;

    char *request;
    request = (char *)calloc(size, sizeof(char));
    if (NULL == request) {
        log_message(ERR, NOCLASS, STR_FUNC_D_FAIL_M, __func__, "calloc", size);
        gf_xdr_free(gf_xdr_auth, (void *)&auth);
        gf_xdr_free(gf_xdr_request, &peekRequest);
	return NULL;
    }

    XDR xdrs;
    xdrmem_create(&xdrs, request, size, XDR_ENCODE);

    struct header tohdr, outhdr;
    gf_init_header(&tohdr);
    tohdr.reqcode = BATCH_JOB_PEEK;
    if (!gf_xdr_message(&xdrs, &peekRequest, &tohdr, &auth, gf_xdr_request, NULL)) {
        log_message(ERR, NOCLASS, STR_FUNC_FAIL, __func__, "gf_xdr_message");
        gf_xdr_free(gf_xdr_auth, (void *)&auth);
        gf_xdr_free(gf_xdr_request, &peekRequest);
	xdr_destroy(&xdrs);
        FREEUP(request);
	return NULL;
    }

    char *master;
    master = qp_getmastername();
    if (NULL == master) {
        master = g_masterlist;
    }

    char *reply;
    int cc, fd;
    cc = gf_callmaster(master, g_js_port, g_conntimeout, g_recvtimeout, g_connretries,
                       XDR_GETPOS(&xdrs), request, &outhdr, &reply, &fd);

    gf_xdr_free(gf_xdr_auth, (void *)&auth);
    gf_xdr_free(gf_xdr_request, &peekRequest);
    xdr_destroy(&xdrs);
    FREEUP(request);
    if (fd > 0) {
        gf_chan_close(fd);
    }

    if (cc < 0) {
        log_message(ERR, NOCLASS, STR_FUNC_FAIL, __func__, "gf_callmaster");
        return NULL;
    }

    quickpool_errno = outhdr.reqcode;
    if (quickpool_errno != 0) {
        xdrmem_create(&xdrs, reply, outhdr.length, XDR_DECODE);

        char *sp = NULL;
        if (!gf_xdr_string(&xdrs, &sp, &outhdr, NULL)) {
            xdr_destroy(&xdrs);
            FREEUP(reply);
            log_message(ERR, NOCLASS, STR_FUNC_FAIL, __func__, "gf_xdr_string");
            return NULL;
        }

        if (sp != NULL) 
            log_message(ERR, NOCLASS, "%s", sp);
        else 
            log_message(ERR, NOCLASS, "%s: unknown error occurs.", __func__);

        FREEUP(sp);
        xdr_destroy(&xdrs);
        FREEUP(reply);
        return NULL;
    }

    char fnBuf[PATH_MAX];
    struct passwd pw, *result;
    struct stat st;
    xdrmem_create(&xdrs, reply, outhdr.length, XDR_DECODE);

    struct QuickPoolPeekReply jobPeekReply;
    if(!libxdr_peek_reply(&xdrs, &jobPeekReply, &outhdr, NULL)) {
        quickpool_errno = ERROR_XDR;
        xdr_destroy(&xdrs);
        FREEUP(reply);
        return NULL;
    }
    xdr_destroy(&xdrs);
    FREEUP(reply);
	
    char buf[200];
    unsigned int bufsize = 200;
    getpwuid_r(getuid(), &pw, buf, bufsize, &result);
    if (NULL == result) {
        quickpool_errno = ERROR_SYS_CALL;
        return NULL;
    }

    log_message(DEBUG, EXECUTE, "%s: the jobReply.outfile is <%s>", 
                __func__, jobPeekReply.output_file);

    snprintf(fnBuf, PATH_MAX, "%s/.quickpool/%s", pw.pw_dir,  jobPeekReply.output_file);
    if (stat(fnBuf, &st) == 0){
        snprintf(jobPeekReply.output_file, PATH_MAX, "%s", fnBuf);
        return(jobPeekReply.output_file);
    }

    if (errno == ENOENT) {
        struct QuickPoolJobInfo *jInfo = NULL;

        struct request jobRequest;
        memset(&jobRequest, 0, sizeof(struct request));

        jobRequest.number = 1;
        jobRequest.keyvalues = (struct keyvalue *)calloc(jobRequest.number,
                                                         sizeof(struct keyvalue));
        if (NULL == jobRequest.keyvalues) {
            log_message(ERR, NOCLASS, STR_FUNC_D_FAIL_M, __func__, "calloc",
                        jobRequest.number*sizeof(struct keyvalue));
            return NULL;
        }

        jobRequest.keyvalues[0].key = REQUEST_KEY_JOBIDS;
        jobRequest.keyvalues[0].value = (char *)calloc(32, sizeof(char));
        if (NULL == jobRequest.keyvalues[0].value) {
            log_message(ERR, NOCLASS, STR_FUNC_D_FAIL_M, __func__, "calloc", 32);
            return NULL;
        }
        snprintf(jobRequest.keyvalues[0].value, 32, "%lld", jobid);

        quickpool_errno = 0;
        struct QuickPoolJobReply *jobReply;
        jobReply = client_get_jobids(&jobRequest, NULL);
        if ((quickpool_errno != 0) || NULL == jobReply || (jInfo = client_get_jobinfo()) == NULL) {
            gf_xdr_free(gf_xdr_request, &jobRequest);
            quickpool_errno = ERROR_JS_INTERNAL;
            return NULL;
        }

        if (NULL != jInfo) {
            gf_xdr_free(libxdr_jobinfo, jInfo);
            FREEUP(jInfo);
        }

        gf_xdr_free(gf_xdr_request, &jobRequest);
        gf_xdr_free(libxdr_job_reply, jobReply);
        FREEUP(jobReply);
        client_finish_getting();

        pid_t pid;
        pid = fork();
        if (0 > pid) {
            return NULL;
        } else if (0 == pid) {

            exit(FALSE);  
        }

        STATUS_WAIT_T status;
        if (waitpid(pid, &status, 0) == -1) {
            return NULL;
        }

        snprintf(fnBuf, PATH_MAX, ".quickpool/%s", jobPeekReply.output_file);
    } else {
        snprintf(fnBuf, PATH_MAX, ".quickpool/%s", jobPeekReply.output_file);
    } 

    snprintf(jobPeekReply.output_file, PATH_MAX, "%s", fnBuf);

    return(jobPeekReply.output_file);
} // end function client_peekjob
